package com.lksoft.bz;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * Print preview dialog
 * 
 * @author lake
 *
 */
public class PrintPreview implements ActionListener, ChangeListener, ItemListener {
	/** Window */
	JFrame window = new JFrame();

	/** The printable target */
	StitchPrinter target;
	/** The page format */
	PageFormat pageFormat;
	
	/** Page currently displaying */
	int currentPage = 0;
	
	/** Page panel */
	JPanel pagePanel;
	/** Page number text field */
	JTextField pageTxt;
	/** Zoom spinner */
	JSpinner zoom;
	/** Show frame checkbox */
	JCheckBox showFrame;
	
	/** Whether there are more pages or not to display */
	private boolean noMorePages;
	
	/**
	 * Font for "no more pages"
	 */
	private static Font font = new Font("monospaced", Font.BOLD, 30);
	
	/**
	 * Create with target and page format
	 * 
	 * @param target
	 * @param pageFormat
	 */
	public PrintPreview(StitchPrinter target, PageFormat pageFormat){
		this.target = target;
		this.pageFormat = pageFormat;
	}
	
	/**
	 * Show the print preview dialog
	 */
	public void show(){
		createWindow();
		window.setResizable(false);
		window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		window.setVisible(true);
	}

	/**
	 * Create the window contents
	 */
	private void createWindow() {
		// Border layout
		window.getContentPane().setLayout(new BorderLayout());
		
		// Top panel
		JPanel topPanel = new JPanel(new FlowLayout());
		
		// Zoom spinner
		zoom = new JSpinner();
		zoom.setPreferredSize(new Dimension(70, 20));
		zoom.setModel(new SpinnerNumberModel(target.getZoom(), 1.0, 9.0, 0.1));
		zoom.addChangeListener(this);
		// Label
		JLabel zoomLabel = new JLabel(Bz.getUIString("printpreview.zoom"));
		
		// Show Frame checkbox
		showFrame = new JCheckBox(Bz.getUIString("printpreview.showframe"));
		showFrame.setSelected(target.isShowFrame());
		showFrame.addItemListener(this);
		
		JButton pageSetup = new JButton(Bz.getUIString("actions.pagesetup.name"));
		JButton print = new JButton(Bz.getUIString("actions.print.name"));
		JButton prev = new JButton("<<<");
		JButton next = new JButton(">>>");
		
		pageSetup.setActionCommand("pagesetup");
		print.setActionCommand("print");
		prev.setActionCommand("prev");
		next.setActionCommand("next");
		
		pageSetup.addActionListener(this);
		print.addActionListener(this);
		prev.addActionListener(this);
		next.addActionListener(this);
		
		pageTxt = new JTextField(""+currentPage);
		pageTxt.setEditable(false);
		
		topPanel.add(showFrame);
		topPanel.add(zoomLabel);
		topPanel.add(zoom);
		topPanel.add(pageSetup);
		topPanel.add(print);
		topPanel.add(prev);
		topPanel.add(pageTxt);
		topPanel.add(next);
		
		// Center panel
		pagePanel = new JPanel(){
			private static final long serialVersionUID = 7757355470843247115L;

			@Override
			public void paint(Graphics g){
				try {
					g.setColor(Color.WHITE);
					g.fillRect(0, 0, getWidth(), getHeight());
					
					if( target.print(g, pageFormat, currentPage) == Printable.NO_SUCH_PAGE ){
						String msg = Bz.getUIString("printpreview.nomorepages");
						FontMetrics m = g.getFontMetrics(font);
						int w = m.stringWidth(msg);
						int h = m.getHeight();
						
						g.setColor(Color.RED);
						g.setFont(font);
						g.drawString(msg, (getWidth()-w)/2, (getHeight()-h)/2);
						
						noMorePages = true;
					}
					else{
						noMorePages = false;
					}
					
					// Print margin lines
					g.setColor(Color.BLACK);
					int imgX = (int) pageFormat.getImageableX();
					int imgY = (int) pageFormat.getImageableY();
					int imgW = (int) pageFormat.getImageableWidth();
					int imgH= (int) pageFormat.getImageableHeight();
					g.drawLine(imgX, imgY, imgX+imgW, imgY);
					g.drawLine(imgX, imgY, imgX, imgY+imgH);
					g.drawLine(imgX+imgW, imgY, imgX+imgW, imgY+imgH);
					g.drawLine(imgX, imgY+imgH, imgX+imgW, imgY+imgH);
				} catch (PrinterException e) {
					e.printStackTrace();
				}
			}
		};
		pagePanel.setPreferredSize(new Dimension((int)pageFormat.getWidth(), (int)pageFormat.getHeight()));
		JScrollPane centerPane = new JScrollPane(pagePanel);
		
		window.getContentPane().add(topPanel, BorderLayout.NORTH);
		window.getContentPane().add(centerPane, BorderLayout.CENTER);
		window.pack();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		switch(e.getActionCommand()){
		case "pagesetup":
			PrinterJob job = PrinterJob.getPrinterJob();
			pageFormat = job.pageDialog(pageFormat);
			pagePanel.setPreferredSize(new Dimension((int)pageFormat.getWidth(), (int)pageFormat.getHeight()));
			pagePanel.revalidate();
			window.pack();
			window.repaint();
			break;
			
		case "print":
			job = PrinterJob.getPrinterJob();
			job.setPrintable(target, pageFormat);
			if( job.printDialog() ){
				try {
					job.print();
					window.dispose();
				} catch (PrinterException e1) {
					JOptionPane.showMessageDialog(window, Bz.getUIString("messages.errors.cantprint"));
				}
			}
			break;
			
		case "prev":
			if( currentPage > 0 ) {
				currentPage--;
				pageTxt.setText(""+currentPage);
				window.repaint();
			}
			break;
			
		case "next":
			if( noMorePages ) return;
			currentPage++;
			pageTxt.setText(""+currentPage);
			window.repaint();
			break;
		}
	}

	@Override
	public void stateChanged(ChangeEvent e) {
		if( e.getSource() == zoom ){
			target.setZoom((float) (double)zoom.getValue());
			window.repaint();
		}
	}

	@Override
	public void itemStateChanged(ItemEvent e) {
		if( e.getSource() == showFrame ){
			target.setShowFrame(e.getStateChange() == ItemEvent.SELECTED);
			window.repaint();
		}
	}
}
